#region Copyright Jonathan Quiros

//	
// All rights are reserved. Reproduction or transmission in whole or in 
// part, in any form or by any means, electronic, mechanical or otherwise, 
// is prohibited without the prior written consent of the copyright owner.
//
// Filename: PartiesLogic.cs
//

#endregion

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using Ids.Utils;
using Ids.Web.Listing;
using Novagoal.Models;
using Novagoal.Models.Utils;
using Novagoal.Repositories;

namespace Novagoal.Logic
{
    public class PartiesLogic : BaseLogic
    {
        #region CONSTANTS

        

        #endregion

        #region PROPERTIES

        private readonly IPartiesRepository _partiesRepository;
        private readonly ITournamentsRepository _tournamentsRepository;

        #endregion

        #region PUBLIC METHODS

        public PartiesLogic(IPartiesRepository partiesRepository, ITournamentsRepository tournamentsRepository)
        {
            _partiesRepository = partiesRepository;
            _tournamentsRepository = tournamentsRepository;
        }

        public List<Ranking> GetGeneralRankings(int personId)
        {
            var list = new List<Ranking>();
            var parties = _partiesRepository.GetParties(personId);
            var tournaments = parties.Select(p => p.Tournament.Id).Distinct().ToList();
            foreach (var tournamentId in tournaments)
            {
                var rankingEntries = _partiesRepository.GetPeopleTournament(tournamentId);
                list.Add(new Ranking
                             {
                                 RankingEntries = rankingEntries
                             });
            }


            return list;
        }

        public List<Ranking> GetRankings(int personId)
        {
            var parties = _partiesRepository.GetParties(personId);
            return (from party in parties
                    let rankingEntries = _partiesRepository.GetPeopleRanking(party.Id)
                    select new Ranking
                               {
                                   Party = party, 
                                   RankingEntries = rankingEntries
                               }).ToList();
        }

        public Ranking GetRanking(int partyId)
        {
            return new Ranking
                       {
                           Party = GetParty(partyId),
                           RankingEntries = _partiesRepository.GetPeopleRanking(partyId)
                       };
        }

        public Dictionary<Tournament, List<RankingEntry>> GetGlobalRankings(int personId)
        {
            var dictionary = new Dictionary<Tournament, List<RankingEntry>>();

            var tournaments = _tournamentsRepository.GetTournamentsByPerson(personId);
            foreach (var tournament in tournaments)
            {
                var rankingEntryList = _partiesRepository.GetPeopleTournament(tournament.Id);
                dictionary.Add(tournament, rankingEntryList);
            }

            return dictionary;
        }

        public PartyList GetParties(NameValueCollection filters, string sort, string direction, int currentPage, int pageSize)
        {
            PartyListSortField sortField;
            SortDirectionType sortDirection;
            Dictionary<PartyListFilter, string> filterList;

            try
            {
                //Sorting based on parameters
                sortField = sort.ToEnumValue<PartyListSortField>();
                sortDirection = direction.ToEnumValue<SortDirectionType>();
                filterList = ParseFilters<PartyListFilter>(filters);
            }
            catch
            {
                //Default Sorting
                filterList = null;
                sortField = PartyListSortField.Id;
                sortDirection = SortDirectionType.Descending;
            }

            var items = _partiesRepository.GetParties(filterList, sortField, sortDirection, currentPage, pageSize);
            var count = _partiesRepository.GetTotalParties(filterList);

            var partyList = new PartyList
            {
                CurrentPage = currentPage,
                Filters = filterList,
                Items = items,
                SortDirection = sortDirection,
                SortField = sortField
            };
            partyList.CalculatePagination(count, pageSize, currentPage);

            return partyList;
        }

        public List<KeyValuePair<int, Person>> GetAllPartyMembers()
        {
            var partiesId = _partiesRepository.GetPartiesId();
            return (from partyId in partiesId
                    let membersinParty = _partiesRepository.GetPartyMembers(partyId)
                    from person in membersinParty
                    select new KeyValuePair<int, Person>(partyId, person)).ToList();

            // Linq conversion
            //foreach (var partyId in partiesId)
            //{
            //    var membersinParty = _partiesRepository.GetPartyMembers(partyId);
            //    foreach (var person in membersinParty)
            //    {
            //        members.Add(new KeyValuePair<int, Person>(partyId, person));
            //    }
            //}
            //return members;
        }

        public Party GetParty(int partyId)
        {
            return _partiesRepository.GetParty(partyId);
        }

        public int Save(Party party)
        {
            return party.Id == 0 ? _partiesRepository.AddParty(party) : _partiesRepository.EditParty(party);
        }

        public List<Person> GetPartyMembers(int partyId)
        {
            return _partiesRepository.GetPartyMembers(partyId);
        }

        public bool IsPersonAMember(int partyId, int personId)
        {
            var members = GetPartyMembers(partyId);
            return members.Any(m => m.Id == personId);
        }

        public List<Person> GetPeopleNotInParty(int partyId)
        {
            return _partiesRepository.GetPeopleNotInParty(partyId);
        }

        public void AddMembers(IEnumerable<int> memberIds, int partyId)
        {
            if (memberIds == null) return;

            var members = _partiesRepository.GetPartyMembers(partyId);
            foreach (var personId in memberIds.Where(personId => !members.Any(m => m.Id == personId)))
            {
                _partiesRepository.AddPartyMember(personId, partyId);
            }
        }

        public void SetFavoriteTeam(int partyId, int teamId, int personId)
        {
            _partiesRepository.SetFavoriteTeam(partyId, teamId, personId);
        }

        public Team GetFavoriteTeam(int personId, int partyId)
        {
            return _partiesRepository.GetFavoriteTeam(personId, partyId);
        }

        public void AddMessage(int partyId, int personId, string message)
        {
            if(IsPersonAMember(partyId, personId))
            {
                _partiesRepository.AddMessage(partyId, personId, message);
            }
            else
            {
                throw new UnauthorizedAccessException(string.Format("The user {0} is not a member of the party {1}",
                                                                    personId, partyId));
            }
        }

        public List<Message> GetMessages(int partyId)
        {
            return _partiesRepository.GetMessages(partyId);
        }

        #endregion

        #region PRIVATE METHODS

        #endregion
    }
}